
#include <QDebug>
#include <math.h>
#include <VG/vgu.h>
#include "OVGSpriteBatch.h"



OVGSpriteBatch::OVGSpriteBatch( int width, int height ) : SpriteBatch( width,height )
{
    lastTextureHandle = VG_INVALID_HANDLE;
    subImage = VG_INVALID_HANDLE;
    paint = VG_INVALID_HANDLE;
}


OVGSpriteBatch::~OVGSpriteBatch()
{
        // cleans up everything
    end();
}

void OVGSpriteBatch::begin(BlendMode bmode, TransformMode dTransform, float *cpm )
{
    tmode = dTransform;
    if (cpm) {
        memcpy(customProjectionMatrix, cpm, sizeof(float) * 16);
    }
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);

#ifdef __OPENVGHEADERS_USE_VG_1_1
    vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
#else
    paint = vgCreatePaint();
    vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
    vgSetPaint(paint, VG_FILL_PATH );

    vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_MULTIPLY);

#endif

    switch(bmode)
    {
    case SpriteBatch::eADDITIVE:
        vgSeti(VG_BLEND_MODE, VG_BLEND_ADDITIVE);
        break;
    default:
        vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
        break;
    }

}

void OVGSpriteBatch::end()
{
    subImageSource = VG_INVALID_HANDLE;
    if (subImage != VG_INVALID_HANDLE) {
        vgDestroyImage( subImage );
        subImage = VG_INVALID_HANDLE;
    }
#ifdef __OPENVGHEADERS_USE_VG_1_1
    vgSeti(VG_COLOR_TRANSFORM, VG_FALSE);
#else
    vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
    if (paint != VG_INVALID_HANDLE) {
        vgDestroyPaint( paint );
        paint = VG_INVALID_HANDLE;
    }
#endif
    lastTextureHandle = VG_INVALID_HANDLE;
}


VGuint OVGSpriteBatch::setSource( SpriteDrawInfo *sdi, int &widthTarget, int &heightTarget )
{
    if (sdi->textureHandle != lastTextureHandle) {
        lastTextureWidth = vgGetParameteri( sdi->textureHandle, VG_IMAGE_WIDTH );
        lastTextureHeight = vgGetParameteri( sdi->textureHandle, VG_IMAGE_HEIGHT );
        lastTextureHandle = sdi->textureHandle;
    }


    if (sdi->sourcex==0.0f && sdi->sourcey==0.0f && sdi->sourceWidth==1.0f && sdi->sourceHeight==1.0f)
    {
        widthTarget = lastTextureWidth;
        heightTarget = lastTextureHeight;
        return sdi->textureHandle;
    }

    // NOT using the whole source, return a subimage within the requested area.
    int sx = sdi->sourcex * lastTextureWidth;
    int sy = sdi->sourcey * lastTextureHeight;
    int swidth = sdi->sourceWidth * lastTextureWidth;
    int sheight = sdi->sourceHeight * lastTextureHeight;

    // do we need to recreate the subimage
    if (subImageSource!=lastTextureHandle || sx!=subx || sy!=suby || swidth!=subWidth || sheight!=subHeight) {
        if (subImage!=VG_INVALID_HANDLE) vgDestroyImage( subImage );
        subx = sx;
        suby = sy;
        subWidth = swidth;
        subHeight = sheight;
        subImageSource = lastTextureHandle;
        subImage = vgChildImage(lastTextureHandle, sx,sy,swidth,sheight );
        //qDebug() << "generated new subimage: " << subx << "," << suby << " w:" << subWidth << " h:" << subHeight;
    }
    widthTarget = subWidth;
    heightTarget = subHeight;
    return subImage;
}


void OVGSpriteBatch::draw( SpriteDrawInfo *sdi, int count )
{
    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE );

    while (count>0) {
        int sourcew, sourceh;
        VGuint handle = setSource(sdi, sourcew, sourceh );

        vgLoadIdentity();

        float tposx, tposy;
        float sizex, sizey;



        if(sdi->manualTransformActive)
        {
                // Can be done with multmatrix alone,.. currently hacked to work with atan
            //vgMultMatrix(&sdi->manualTransformMatrix[0][0]);


            sdi->scaleX = sqrtf( sdi->manualTransformMatrix[0][0] * sdi->manualTransformMatrix[0][0] +
                                 sdi->manualTransformMatrix[0][1] * sdi->manualTransformMatrix[0][1] );

            sdi->scaleY = sqrtf( sdi->manualTransformMatrix[1][0] * sdi->manualTransformMatrix[1][0] +
                                 sdi->manualTransformMatrix[1][1] * sdi->manualTransformMatrix[1][1] );


            //sdi->scaleX = 100.0f;
            //sdi->scaleY = 100.0f;

            sdi->angle = atan2( sdi->manualTransformMatrix[1][0], sdi->manualTransformMatrix[1][1] );


        }



        if (tmode == eCUSTOMPROJECTION) {
                // NOTE: INITIAL VERSION OF THE CUSTOM PROJECTION
                // The transform must be fixed.
            tposx = (float)((1.0f + sdi->posx*customProjectionMatrix[0])*0.5f)  * targetWidth;
            tposy = (float)((1.0f + sdi->posy*customProjectionMatrix[5])*0.5f)  * targetHeight;
            sizex = sdi->scaleX * targetWidth * customProjectionMatrix[0] * 0.5f;
            sizey = sdi->scaleY * targetHeight * customProjectionMatrix[5] * 0.5f;


        } else {
            tposx = sdi->posx;
            tposy = sdi->posy;
            sizex = sdi->scaleX;
            sizey = sdi->scaleY;

        }





//        vgScale(targetWidth, targetHeight);
        vgTranslate( tposx , tposy );



        vgRotate( sdi->angle*360.0f / (3.14159f*2.0f) );
        vgScale( sizex/(float)sourcew, -sizey/(float)sourceh );


        vgTranslate( -(float)sourcew*sdi->originX, -(float)sourceh*sdi->originY );


/*
*/
#ifdef __OPENVGHEADERS_USE_VG_1_1
        VGfloat colors[8]={
            sdi->r, sdi->g, sdi->b, sdi->a,
            0,0,0,0,
        };
        vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, colors);
#else
        vgSetColor(paint,
                   ((VGuint)(sdi->r*255.0f)<<24) |
                   ((VGuint)(sdi->g*255.0f)<<16) |
                   ((VGuint)(sdi->b*255.0f)<<8) |
                   ((VGuint)(sdi->a*255.0f)<<0));
#endif
        vgDrawImage( handle );

        count--;
        sdi++;
    }
}




